package com.kun.common.file.minio;

import com.kun.common.file.core.FileTemplate;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author kun.li
 */
@Slf4j
@RequiredArgsConstructor
public class MinioTemplate implements FileTemplate, InitializingBean {

    private MinioClient minioClient;

    private final MinioProperties minioProperties;


    public boolean bucketExists(String bucketName) throws Exception {
        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }

    public void makeBucket(String bucketName) throws Exception {
        minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
    }

    public String uploadObject(String buckName, String fileName, String filePath) throws Exception {
        ObjectWriteResponse objectWriteResponse = minioClient.uploadObject(
                UploadObjectArgs.builder()
                        .bucket(buckName)
                        .object(fileName)
                        .filename(filePath)
                        .build());
        return objectWriteResponse.object();
    }

    public ObjectWriteResponse createBucketFolder(String folderName) throws Exception {
        return createBucketFolder(minioProperties.getBuckName(), folderName);
    }

    public ObjectWriteResponse createBucketFolder(String buckName, String folderName) throws Exception {
        String object = folderName;
        if (!object.equals("/")) {
            object = folderName + "/";
        }
        return minioClient.putObject(PutObjectArgs.builder()
                .bucket(buckName)
                .object(object)
                .stream(new ByteArrayInputStream(new byte[0]), 0, 0)
                .build());
    }

    public void removeObject(String objectName) throws Exception {
        removeObject(minioProperties.getBuckName(), objectName);
    }

    public void removeObject(String buckName, String objectName) throws Exception {
        minioClient.removeObject(RemoveObjectArgs.builder().bucket(buckName).object(objectName).build());
    }

    public void deleteBucket(String buckName) throws Exception {
        minioClient.removeBucket(RemoveBucketArgs.builder().bucket(buckName).build());

    }

    public List<Bucket> getAllBucketInfo() throws Exception {
        return minioClient.listBuckets();
    }

    public Iterable<Result<Item>> getBucketAllFile(String buckName, String folderName, Boolean isDeep) throws Exception {
        return minioClient.listObjects(ListObjectsArgs.builder()
                .bucket(buckName)
                .prefix(folderName + "/")
                .recursive(isDeep)
                .build());

    }

    /**
     * 共享给其他地址使用
     *
     * @param bucketName
     * @param objectName
     * @param expires
     * @return
     * @throws Exception
     */
    public String getFileUploadUrl(String bucketName, String objectName, int expires) throws Exception {
        return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .method(Method.GET)
                .expiry(expires, TimeUnit.DAYS)
                .build());
    }

    public ObjectWriteResponse fileUpload(String fileAbsolutePath, InputStream inputStream, long objectSize, String contentType) throws Exception {
        return fileUpload(minioProperties.getBuckName(), fileAbsolutePath, inputStream, objectSize, contentType);
    }

    public ObjectWriteResponse fileUpload(String buckName, String fileAbsolutePath, InputStream inputStream, long objectSize, String contentType) throws Exception {
        return minioClient.putObject(PutObjectArgs.builder()
                .bucket(buckName)
                .object(fileAbsolutePath)
                .stream(inputStream, objectSize, -1)
                .contentType(contentType)
                .build());
    }

    public GetObjectResponse getResponse(String object) throws Exception {
        return getResponse(minioProperties.getBuckName(), object);
    }

    public GetObjectResponse getResponse(String buckName, String object) throws Exception {
        return minioClient.getObject(GetObjectArgs.builder()
                .bucket(buckName)
                .object(object)
                .build());
    }

    public ObjectWriteResponse copyFile(String sourceObject, String targetObject) throws Exception {
        return copyFile(minioProperties.getBuckName(), sourceObject, minioProperties.getBuckName(), targetObject);
    }

    public ObjectWriteResponse copyFile(String sourceObject, String targetBuckName, String targetObject) throws Exception {
        return copyFile(minioProperties.getBuckName(), sourceObject, targetBuckName, targetObject);
    }

    public ObjectWriteResponse copyFile(String sourceBuckName, String sourceObject, String targetBuckName, String targetObject) throws Exception {
        return minioClient.copyObject(CopyObjectArgs.builder()
                .source(CopySource.builder()
                        .bucket(sourceBuckName)
                        .object(sourceObject)
                        .build())
                .bucket(targetBuckName)
                .object(targetObject)
                .build());
    }

    public boolean checkBuckFileExist(String objectName) {
        try {
            return bucketExists(minioProperties.getBuckName()) && minioClient.statObject(StatObjectArgs.builder().bucket(minioProperties.getBuckName()).object(objectName).build()) != null;
        } catch (Exception e) {
            log.error("文件不存在", e);
            return false;
        }
    }

    public boolean checkBuckFileExist(String bucketName, String objectName) {
        try {
            return bucketExists(bucketName) && minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build()) != null;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public String buildMinioAddress() {
        return minioProperties.getEndpoint() + "/" + minioProperties.getBuckName();
    }


    @Override
    public void afterPropertiesSet() {
        this.minioClient = MinioClient.builder()
                .endpoint(minioProperties.getEndpoint())
                .credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
                .build();
    }

    public static void main(String[] args) throws Exception {
        MinioProperties minIoProperties1 = new MinioProperties();
        minIoProperties1.setEndpoint("http://192.168.56.3:9000");
        minIoProperties1.setBuckName("kun");
        minIoProperties1.setAccessKey("admin");
        minIoProperties1.setSecretKey("admin123456");
        MinioTemplate minioTemplate = new MinioTemplate(minIoProperties1);
        minioTemplate.afterPropertiesSet();
    }
}
